all repos — caroster @ f86e1749937206e0137333460508ec947ace71b4

[Octree] Group carpool to your event https://caroster.io

frontend/pages/e/[uuid]/details.tsx (view raw)

  1import moment from 'moment';
  2import Button from '@mui/material/Button';
  3import Box from '@mui/material/Box';
  4import Link from '@mui/material/Link';
  5import Paper from '@mui/material/Paper';
  6import Divider from '@mui/material/Divider';
  7import Container from '@mui/material/Container';
  8import TextField from '@mui/material/TextField';
  9import Typography from '@mui/material/Typography';
 10import {useTheme} from '@mui/material/styles';
 11import {DatePicker} from '@mui/x-date-pickers/DatePicker';
 12import {PropsWithChildren, useState} from 'react';
 13import {useTranslation} from 'react-i18next';
 14import pageUtils from '../../../lib/pageUtils';
 15import ShareEvent from '../../../containers/ShareEvent';
 16import useEventStore from '../../../stores/useEventStore';
 17import useToastStore from '../../../stores/useToastStore';
 18import useSettings from '../../../hooks/useSettings';
 19import EventLayout, {TabComponent} from '../../../layouts/Event';
 20import {
 21  EventByUuidDocument,
 22  useUpdateEventMutation,
 23} from '../../../generated/graphql';
 24
 25interface Props {
 26  eventUUID: string;
 27  announcement?: string;
 28}
 29
 30const Page = (props: PropsWithChildren<Props>) => {
 31  return <EventLayout {...props} Tab={DetailsTab} />;
 32};
 33
 34const DetailsTab: TabComponent = ({}) => {
 35  const {t} = useTranslation();
 36  const theme = useTheme();
 37  const settings = useSettings();
 38  const [updateEvent] = useUpdateEventMutation();
 39  const addToast = useToastStore(s => s.addToast);
 40  const setEventUpdate = useEventStore(s => s.setEventUpdate);
 41  const event = useEventStore(s => s.event);
 42  const [isEditing, setIsEditing] = useState(false);
 43  const idPrefix = isEditing ? 'EditEvent' : 'Event';
 44
 45  const onSave = async e => {
 46    try {
 47      const {uuid, ...data} = event;
 48      const {id, travels, waitingPassengers, __typename, ...input} = data;
 49      await updateEvent({
 50        variables: {uuid, eventUpdate: input},
 51        refetchQueries: ['eventByUUID'],
 52      });
 53      setIsEditing(false);
 54    } catch (error) {
 55      console.error(error);
 56      addToast(t('event.errors.cant_update'));
 57    }
 58  };
 59  const sectionSx = {
 60    marginBottom: theme.spacing(2),
 61    width: '540px',
 62    maxWidth: '100%',
 63    paddingX: theme.spacing(2),
 64  };
 65
 66  const modifyButton = isEditing ? (
 67    <Button
 68      variant="contained"
 69      color="primary"
 70      sx={{position: 'absolute', right: theme.spacing(2)}}
 71      onClick={onSave}
 72    >
 73      {t('event.details.save')}
 74    </Button>
 75  ) : (
 76    <Button
 77      variant="text"
 78      color="primary"
 79      sx={{position: 'absolute', right: theme.spacing(2)}}
 80      onClick={() => setIsEditing(true)}
 81    >
 82      {t('event.details.modify')}
 83    </Button>
 84  );
 85
 86  if (!event) return null;
 87
 88  return (
 89    <Box
 90      sx={{
 91        position: 'relative',
 92        paddingLeft: '80px',
 93
 94        [theme.breakpoints.down('md')]: {
 95          paddingLeft: 0,
 96          paddingBottom: '80px',
 97        },
 98      }}
 99    >
100      <Container maxWidth="sm" sx={{marginTop: theme.spacing(6)}}>
101        <Paper sx={{position: 'relative', padding: theme.spacing(2)}}>
102          {modifyButton}
103          <Box sx={sectionSx}>
104            <Typography variant="h6">{t('event.fields.name')}</Typography>
105            {isEditing ? (
106              <TextField
107                fullWidth
108                value={event.name}
109                onChange={e => setEventUpdate({name: e.target.value})}
110                name="name"
111                id="EditEventName"
112              />
113            ) : (
114              <Typography variant="body1" id={`${idPrefix}Name`}>
115                {event.name ?? t('event.fields.empty')}
116              </Typography>
117            )}
118          </Box>
119          <Box sx={sectionSx}>
120            <Typography variant="h6">{t('event.fields.date')}</Typography>
121            {isEditing ? (
122              <DatePicker
123                renderInput={props => (
124                  <TextField
125                    {...props}
126                    id={`${idPrefix}Date`}
127                    fullWidth
128                    placeholder={t('event.fields.date_placeholder')}
129                  />
130                )}
131                inputFormat="DD/MM/yyyy"
132                value={event.date}
133                onChange={date =>
134                  setEventUpdate({
135                    date: !date ? null : moment(date).format('YYYY-MM-DD'),
136                  })
137                }
138              />
139            ) : (
140              <Typography variant="body1" id={`${idPrefix}Date`}>
141                {event.date
142                  ? moment(event.date).format('DD/MM/YYYY')
143                  : t('event.fields.empty')}
144              </Typography>
145            )}
146          </Box>
147          <Box sx={sectionSx}>
148            <Typography variant="h6">{t('event.fields.address')}</Typography>
149            {isEditing ? (
150              <TextField
151                fullWidth
152                multiline
153                maxRows={4}
154                inputProps={{maxLength: 250}}
155                helperText={`${event.address?.length ?? 0}/250`}
156                defaultValue={event.address}
157                value={event.address}
158                onChange={e => setEventUpdate({address: e.target.value})}
159                id={`${idPrefix}Address`}
160                name="address"
161              />
162            ) : (
163              <Typography variant="body1" id={`${idPrefix}Address`}>
164                {event.address ? (
165                  <Link
166                    target="_blank"
167                    rel="noreferrer"
168                    href={`https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(
169                      event.address
170                    )}`}
171                    onClick={e => e.preventDefault}
172                  >
173                    {event.address}
174                  </Link>
175                ) : (
176                  t('event.fields.empty')
177                )}
178              </Typography>
179            )}
180          </Box>
181          <Box sx={sectionSx}>
182            <Typography variant="h6">
183              {t('event.fields.description')}
184            </Typography>
185            {isEditing ? (
186              <TextField
187                fullWidth
188                multiline
189                maxRows={4}
190                inputProps={{maxLength: 250}}
191                helperText={`${event.description?.length || 0}/250`}
192                defaultValue={event.description}
193                value={event.description || ''}
194                onChange={e => setEventUpdate({description: e.target.value})}
195                id={`${idPrefix}Description`}
196                name="description"
197              />
198            ) : (
199              <Typography variant="body1" id={`${idPrefix}Description`}>
200                {event.description ?? t('event.fields.empty')}
201              </Typography>
202            )}
203          </Box>
204          <Box sx={sectionSx}>
205            <Typography variant="h6">{t('event.fields.link')}</Typography>
206            <Typography>{t('event.fields.link_desc')}</Typography>
207          </Box>
208          <Box py={4} justifyContent="center" display="flex">
209            <ShareEvent
210              title={`Caroster ${event.name}`}
211              url={`${window.location.href}`}
212            />{' '}
213          </Box>
214          <Divider variant="middle" />
215          <Box pt={2} justifyContent="center" display="flex">
216            <Link href={settings?.about_link} target="_blank" rel="noopener">
217              {t('event.details.aboutCaroster')}
218            </Link>
219          </Box>
220        </Paper>
221      </Container>
222    </Box>
223  );
224};
225
226export const getServerSideProps = pageUtils.getServerSideProps(
227  async (context, apolloClient) => {
228    const {uuid} = context.query;
229    const {host = ''} = context.req.headers;
230    let event = null;
231
232    // Fetch event
233    try {
234      const {data} = await apolloClient.query({
235        query: EventByUuidDocument,
236        variables: {uuid},
237      });
238      event = data?.eventByUUID?.data;
239    } catch (error) {
240      return {
241        notFound: true,
242      };
243    }
244
245    return {
246      props: {
247        eventUUID: uuid,
248        metas: {
249          title: event?.attributes?.name || '',
250          url: `https://${host}${context.resolvedUrl}`,
251        },
252      },
253    };
254  }
255);
256export default Page;